﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using static UnityEngine.DebugLogConfig;
using System.Text;
using System.Text.RegularExpressions;
using LitJson;


namespace UnityEngine
{
    public class Debuger
    {
        /// <summary>
        /// 调用深度
        /// </summary>
        public const int CallDeepin = 4;

        #region 日志设置
        /// <summary>
        /// 是否输入堆栈信息(代码位置以及脚本名称)
        /// </summary>
        public static bool EnadleStack = false;
        /// <summary>
        /// 日志文件名
        /// </summary>
        public static string LogFileName = "";
        /// <summary>
        /// 日志文件目录
        /// </summary>
        public static string LogFileDir = "";

        private static StreamWriter LogWrite;
        #endregion

        // 打印配置
        private static Dictionary<string, DebugLogConfig> WriteConfig = new Dictionary<string, DebugLogConfig>();

        #region 实例成员
        private DebugLogConfig logConfig;
        private string tag;

        private Debuger() { }

        /// <summary>
        /// 启用日志
        /// </summary>
        /// <param name="type">当前脚本</param>
        /// <returns></returns>
        public static Debuger GetLogger(Type type)
        {
            var deBug = new Debuger
            {
                logConfig = GetConfig(type.FullName),
                tag = type.FullName
            };
            return deBug;
        }



        /// <summary>
        /// 打印消息日志
        /// </summary>
        /// <param name="logInfo">日志内容</param>
        /// <param name="_strParams">扩展内容</param>
        public void L(string logInfo, params object[] _strParams)
        {
            if (logConfig != null && (logConfig.LogType & DebugLogType.INFO) > 0)
            {
                Print(logInfo, tag, logConfig, DebugLogType.INFO, _strParams);
            }
        }

        /// <summary>
        /// 打印警告日志
        /// </summary>
        /// <param name="warningInfo"> 日志内容 </param>
        /// <param name="_strParams"> 扩展内容 </param>
        public void W(string warningInfo, params object[] _strParams)
        {
            if (logConfig != null && (logConfig.LogType & DebugLogType.WARNING) > 0)
            {
                Print(warningInfo, tag, logConfig, DebugLogType.WARNING, _strParams);
            }
        }

        /// <summary>
        /// 打印错误日志
        /// </summary>
        /// <param name="erroeInfo"> 日志内容 </param>
        /// <param name="_strParams"> 扩展内容 </param>
        public void E(string erroeInfo, params object[] _strParams)
        {
            if (logConfig != null && (logConfig.LogType & DebugLogType.ERROR) > 0)
            {
                Print(erroeInfo, tag, logConfig, DebugLogType.ERROR, _strParams);
            }
        }

        #endregion

        #region 静态方法

        private static void Print(string dataInfo, string tag, DebugLogConfig debugConfig, DebugLogType logType, params object[] _strParams)
        {
            Print(string.Format(dataInfo, _strParams), tag, debugConfig, logType);
        }

        private static void Print(string dataInfo, string tag, DebugLogConfig debugConfig, DebugLogType logType)
        {

            var callLine = GetCallLine();
            var callFineName = Path.GetFileName(GetCallNames());
            string log = string.Format(LogInfoTemplateByColor(logType), DateTime.Now, tag, dataInfo, callFineName, callLine);
            switch (logType) //在Unity中打印信息
            {
                case DebugLogConfig.DebugLogType.INFO:
                    Debug.Log(log);
                    break;
                case DebugLogConfig.DebugLogType.WARNING:
                    Debug.LogWarning(log);
                    break;
                case DebugLogConfig.DebugLogType.ERROR:
                    Debug.LogError(log);
                    break;
                default:
                    break;
            }

            if (debugConfig.IsFine)
                LogToFine(string.Format(FileTemplate(logType), DateTime.Now, tag, dataInfo, callFineName, callLine)); // 是否输出文件
        }

        /// <summary>
        /// 文件模版
        /// </summary>
        /// <param name="logType"></param>
        /// <returns></returns>
        private static string FileTemplate(DebugLogType logType)
        {
            var builder = new StringBuilder();
            string temp = string.Format("{0,8}", logType);
            builder.Append("{0:yyyy-MM-dd HH:mm:ss:fff}[" + temp + "]{1}>{2}    ==>  ");
            if (EnadleStack)
                builder.Append("\n{3}:{4}");
            return builder.ToString();
        }

        /// <summary>
        /// 日志信息模版添加颜色
        /// </summary>
        /// <param name="logType"></param>
        /// <returns></returns>
        private static string LogInfoTemplateByColor(DebugLogConfig.DebugLogType logType)
        {
            string color = "";
            string TextColor = "black";
            if (logType == DebugLogType.WARNING)
                TextColor = "yellow";
            if (logType == DebugLogType.ERROR)
                TextColor = "red";
            switch (logType)
            {
                case DebugLogType.INFO:
                    color = "green";
                    break;
                case DebugLogType.WARNING:
                    color = "yellow";
                    break;
                case DebugLogType.ERROR:
                    color = "red";
                    break;
                default:
                    throw new ArgumentOutOfRangeException("logType", logType, null);
            }

            var builder = new StringBuilder();
            builder.Append("<size=12>");
            builder.Append("{0:yyyy-MM-dd HH:mm:ss.fff}");
            builder.Append(" [<color=" + color + ">" + logType + "</color>] ");
            builder.Append("<color=blue>{1}</color>");
            builder.Append("<b><color=green> ==> </color></b><color=" + TextColor + ">{2}</color>");
            builder.Append("</size>");

            if (EnadleStack)
            {
                builder.Append("<size=12>\n{3}:{4}</size>");
            }
            return builder.ToString();
        }

        /// <summary>
        /// 日志到文件
        /// </summary>
        /// <param name="message">消息</param>
        private static void LogToFine(string message)
        {
            if (LogWrite == null)
            {
                var now = DateTime.Now;
                LogFileName = string.Format("{0:yyyy_MM_dd_HH_mm}.log", now);
                var fullPath = LogFileDir + LogFileName;
                try
                {
                    if (!Directory.Exists(LogFileDir))
                    {
                        Directory.CreateDirectory(LogFileDir);
                    }
                    LogWrite = File.AppendText(fullPath);
                    LogWrite.AutoFlush = true;
                }
                catch (Exception e)
                {
                    LogWrite = null;
                    Debug.LogError("LogToCache():" + e.Message + e.StackTrace);
                    return;
                }
            }

            if (LogWrite == null) return;

            try
            {
                LogWrite.WriteLine(message);
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
        }


        /// <summary>
        /// 返回代码行
        /// </summary>
        /// <returns></returns>
        private static int GetCallLine()
        {
            var data = new System.Diagnostics.StackTrace(CallDeepin, true);
            return data.GetFrame(0).GetFileLineNumber();

        }

        /// <summary>
        /// 返回脚本名
        /// </summary>
        /// <returns></returns>
        private static string GetCallNames()
        {
            var data = new System.Diagnostics.StackTrace(CallDeepin, true);
            return data.GetFrame(0).GetFileName();
        }

        /// <summary>
        /// 返回配置
        /// </summary>
        /// <param name="fullName"></param>
        /// <returns></returns>
        private static DebugLogConfig GetConfig(string fullName)
        {
            foreach (var key in WriteConfig.Keys)
            {
                if (Regex.IsMatch(fullName, @"^" + key + @"*$"))
                {
                    return WriteConfig[key];
                }
            }
            return null;
        }

        /// <summary>
        /// 加载配置
        /// </summary>
        /// <param name="json"></param>
        public static void LoedConfig(string json)
        {
            JsonData data = JsonMapper.ToObject(json);

            foreach (JsonData item in data)
            {

                DebugLogConfig dlc = new DebugLogConfig();

                dlc.Assembly = item["assembly"].ToString();
                if (!Regex.IsMatch(dlc.Assembly, @"^[a_zA_Z\.]+$"))
                    continue;

                var logType = item["logType"].ToString();
                string[] TypeKey = logType.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                dlc.LogType = 0;
                foreach (var key in TypeKey)
                {
                    DebugLogType dlt = (DebugLogType)Enum.Parse(typeof(DebugLogType), key);
                    dlc.LogType |= dlt;
                }
                dlc.IsFine = bool.Parse(item["isFile"].ToString());
                WriteConfig.Add(dlc.Assembly, dlc);

            }
        }

        #endregion
    }

}
